package com.hyperzsoft.budget;

import java.text.NumberFormat;
import java.util.ArrayList;

import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.hyperzsoft.budget.DBProvider.BudgetTable;
import com.hyperzsoft.budget.DBProvider.Expense;

public class EditExpenses extends ListActivity {
	static private String TAG = "EditExpenses";
	private DBProvider mDBProvider;
	
	private expenseListAdapter mAdapter;
	private ArrayList<Expense> mExpenses = null;
	private ProgressDialog mProgressDialog = null;
	private Dialog mDialog;
	
	private String currentAmount = "$0.00";
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.types_edit_list_view);
				
		mDBProvider = new DBProvider(this);
		mExpenses = new ArrayList<Expense>();
		mAdapter = new expenseListAdapter(this, R.layout.expenses_edit_list_item, mExpenses);
		
		//TODO: handle savedInstanceState
		if (savedInstanceState != null) {
			mAdapter.setSelectedPosition(savedInstanceState.getInt("selectedPos"));
			mExpenses = savedInstanceState.getParcelableArrayList("expenses");
			
			if (savedInstanceState.getBoolean("dialog_isOpen")) {
				//loadDialog(savedInstanceState.getString("dialog_typeName"), savedInstanceState.getInt("dialog_typeColor"));
				//currentAmount = NumberFormat.getCurrencyInstance().format((savedInstanceState.getDouble(BUNDLE_KEY_AMOUNT)));
				
			}
			
			populateAdapter();
		} else {
			setupListAdapter(false);
		}
		
		setupListClicks();
	}
	
	private void setupListAdapter(boolean isReload) {
		(new Thread(null, new Runnable() {
			@Override
			public void run() {
				getExpenseList();
			}
		}, "BudgetThread")).start();
		
		mProgressDialog = ProgressDialog.show(this,    
				"Please wait...", (isReload) ? "Reloading data ..." : "Retrieving data ...", true);
	}
	
	private void populateAdapter() {
		mAdapter.clear();
		setListAdapter(mAdapter);
		
		for(int i=0;i<mExpenses.size();i++)
			mAdapter.add(mExpenses.get(i));
		
		mAdapter.notifyDataSetChanged();
	}
	
	private final Runnable returnRes = new Runnable() {
		@Override
		public void run() {
			if(mExpenses != null && mExpenses.size() > 0){
				populateAdapter();
			}
			
			if (mProgressDialog.isShowing()) mProgressDialog.dismiss();
		}
	};
	
	private void setupListClicks() {
		ListView lv = getListView();
		
		lv.setOnItemSelectedListener(new OnItemSelectedListener() {
			@Override
			public void onItemSelected(AdapterView<?> parent, View view, 
					int position, long id) {
				mAdapter.setSelectedPosition(position);
			}
			
			@Override
			public void onNothingSelected(AdapterView<?> parent) {
				//highlight the selected item
				mAdapter.setSelectedPosition(mAdapter.mSelectedPos);
			}
		});
		
		lv.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view,
					int position, long id) {
				
				parent.performItemClick(view, position, id);
				
				loadDialog(mAdapter.getItem(position));
				
				return false;
			}
		});
		
		lv.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				
				//highlight the selected item
				mAdapter.setSelectedPosition(position);
				
			}
		});
	}
	
	private void getExpenseList(){
		ArrayList<Object> workingList = null;
		
		try{
			mExpenses = new ArrayList<Expense>();
			mDBProvider.open();
			workingList = mDBProvider.selectAll(BudgetTable.EXPENSE, "_ID asc", "", null);
			mDBProvider.close();
			
			for (Object obj : workingList){
				mExpenses.add((Expense)obj);
			}
			
			workingList = null;
			
			Thread.sleep(500);
		} catch (Exception e) {
			Log.e(TAG, e.getMessage().toString());
			for (StackTraceElement traceElement : e.getStackTrace()) {
				Log.e(TAG, "  at " + traceElement.toString());
			}
		}
		
		runOnUiThread(returnRes);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		if (mProgressDialog != null){mProgressDialog.cancel();}
	}
	
	@Override
	protected void onSaveInstanceState(Bundle instanceState) {
		//app is either being killed, activity is paused or screen is flipped
		super.onSaveInstanceState(instanceState);
		
		//save the globals we know that affect the display of the list
		instanceState.putInt("selectedPos", mAdapter.getSelectedPosition());
		
		instanceState.putBoolean("dialog_isOpen", mDialog.isShowing());
		//TODO: save the dialog values
		
		instanceState.putParcelableArrayList("expense", mExpenses);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		try {
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.edit_expenses_menu, menu);
			return true;
		} catch (Exception e) {
			Log.e(TAG, e.getMessage().toString());
			for (StackTraceElement traceElement : e.getStackTrace()) {
				Log.e(TAG, "  at " + traceElement.toString());
			}
			return false;
		}
	}
    
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		try {
			// Handle item selection
			switch (item.getItemId()) {
			case R.id.type_add:
				mAdapter.setSelectedPosition(-1);
				loadDialog(mDBProvider.new Expense());
				return true;
			case R.id.type_edit:
				if (mAdapter.getSelectedPosition() != -1) {
					loadDialog();
				} else {
					Toast.makeText(getApplicationContext(), "No item is selected!", Toast.LENGTH_SHORT).show();
				}
				return true;
			case R.id.type_delete:
				if (mAdapter.getSelectedPosition() != -1) {
					Expense expense = mDBProvider.new Expense();
					expense._ID = mAdapter.getSelectedItemID();
					//TODO: do we need to confirm the delete?
					expense.delete();
				} else {
					Toast.makeText(getApplicationContext(), "No item is selected!", Toast.LENGTH_SHORT).show();
				}
				setupListAdapter(true);
				return true;
			case R.id.type_switch:
				mAdapter.setSelectedPosition(-1);
				setupListAdapter(true);
				return true;
			case R.id.type_refresh:
				setupListAdapter(true);
				return true;
			case R.id.type_back:
				finish();
				return true;
			default:
				return super.onOptionsItemSelected(item);
			}
		} catch (Exception e) {
			Log.e(TAG, e.getMessage().toString());
			for (StackTraceElement traceElement : e.getStackTrace()) {
				Log.e(TAG, "  at " + traceElement.toString());
			}
			return false;
		}
	}
	
	public void loadDialog()
	{
		loadDialog(mAdapter.getItem());
	}
	
	public void loadDialog(Expense expense)
	{
		Cursor cursorGroups;
		Cursor cursorTypes;
		
		cursorGroups = mDBProvider.getSpinnerCursorGroups();
		cursorTypes = mDBProvider.getSpinnerCursorTypes();
		
		this.startManagingCursor(cursorGroups);
		this.startManagingCursor(cursorTypes);
		
		//setup dialog
		mDialog = new Dialog(this, R.style.EditTypesDialog);
		mDialog.setContentView(R.layout.expenses_edit_dialog_view);	
		mDialog.setCancelable(true);
		mDialog.setOwnerActivity(this);
		
		setupSpinner((Spinner)mDialog.findViewById(R.id.Edit_ExpenseGroup), cursorGroups);
		setupSpinner((Spinner)mDialog.findViewById(R.id.Edit_ExpenseType), cursorTypes);
		
		setupAmountListeners((EditText)mDialog.findViewById(R.id.Edit_ExpenseAmount));
		
		if (expense._ID != -1) {
			((EditText)mDialog.findViewById(R.id.Edit_ExpenseName)).setText(expense.NAME);
			currentAmount = NumberFormat.getCurrencyInstance().format((expense.AMOUNT));
			((EditText)mDialog.findViewById(R.id.Edit_ExpenseAmount)).setText(currentAmount);
			setSpinnerSelection((Spinner)mDialog.findViewById(R.id.Edit_ExpenseGroup), expense.GROUP_ID);
			setSpinnerSelection((Spinner)mDialog.findViewById(R.id.Edit_ExpenseType), expense.TYPE_ID);
		} else {
			((EditText)mDialog.findViewById(R.id.Edit_ExpenseName)).setHint(R.string.Edit_ExpenseName_Hint);
			((EditText)mDialog.findViewById(R.id.Edit_ExpenseAmount)).setHint(R.string.Edit_ExpenseAmount_Hint);
		}
		
		mDialog.show();
		
		((Button)mDialog.findViewById(R.id.Edit_ExpenseSave)).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				//TODO: Validation??
				saveExpenseItem();
			}
		});
		
		((Button)mDialog.findViewById(R.id.Edit_ExpenseCancel)).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				//TODO: Verify if data has changed??
				mDialog.dismiss();
			}
		});
	}
	
	public void saveExpenseItem() {
		
		mDBProvider.open();
		Expense expense = mDBProvider.new Expense();
		
		expense.NAME = ((EditText)mDialog.findViewById(R.id.Edit_ExpenseName)).getText().toString();
		String cleanString = ((EditText)mDialog.findViewById(R.id.Edit_ExpenseAmount)).getText().toString().replaceAll("[$,.]", "");
        expense.AMOUNT = Double.parseDouble(cleanString)/100;
        expense.GROUP_ID = getSpinnerSelection((Spinner)mDialog.findViewById(R.id.Edit_ExpenseGroup));
		expense.TYPE_ID = getSpinnerSelection((Spinner)mDialog.findViewById(R.id.Edit_ExpenseType));
		
		if (mAdapter.getSelectedPosition() == -1) {
			expense.insert();
		} else {
			expense._ID = mAdapter.getSelectedItemID();
			expense.update();
		}
		
		mDBProvider.close();
		
		mDialog.dismiss();
		
		((EditText)mDialog.findViewById(R.id.Edit_ExpenseName)).setText("");
		((EditText)mDialog.findViewById(R.id.Edit_ExpenseAmount)).setText("$0.00");
		
		setupListAdapter(true);
	}
	
	public void setSpinnerSelection(Spinner spinner, long defaultValue) {
		for (int i = 0; i < spinner.getCount(); i++) {
		    Cursor value = (Cursor) spinner.getItemAtPosition(i);
		    long id = value.getLong(value.getColumnIndex("_id"));
		    if (id == defaultValue) {
		        spinner.setSelection(i);
		    }
		}
	}
	
	public long getSpinnerSelection(Spinner spinner) {
		Cursor value = (Cursor) spinner.getItemAtPosition(spinner.getSelectedItemPosition());
		return value.getLong(value.getColumnIndex("_id"));
	}
	
	public void setupSpinner(Spinner spinner, Cursor spinnerCursor) {
		//This is deprecated in API 11
		SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
			    android.R.layout.simple_spinner_item, spinnerCursor, 
			    new String[] {"name"}, 
			    new int[] {android.R.id.text1});
		
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);
	}
	
	private void setupAmountListeners(final EditText amount) {
		amount.addTextChangedListener(new TextWatcher() {
	        public void afterTextChanged(Editable arg0) {
	        }
	        
	        public void beforeTextChanged(CharSequence s, int start,
	                int count, int after) {
	        }
	        
	        public void onTextChanged(CharSequence s, int start, int before, int count) {
	        	if(!s.toString().equals(currentAmount) && !s.toString().equals("$0.00")) {
	               String cleanString = s.toString().replaceAll("[$,.]", "");
	               if (cleanString == "") cleanString = "000";
	               double parsed = Double.parseDouble(cleanString);
	               String formatted = NumberFormat.getCurrencyInstance().format((parsed/100));
	               
	               currentAmount = formatted;
	               amount.setText(formatted);
	               amount.setSelection(formatted.length());
	            }
	        }
		});
	}
	
	public class expenseListAdapter extends ArrayAdapter<Expense> {
		private final ArrayList<Expense> mItems;
		private int mSelectedPos;
		
		public expenseListAdapter(Context context, int textViewResourceId, ArrayList<Expense> items) {
			super(context, textViewResourceId, items);
			this.mItems = items;
			mSelectedPos = -1;
		}
		
		public void setSelectedPosition(int pos){
			
			mSelectedPos = pos;
			// inform the view of this change
			notifyDataSetChanged();
		}
		
		public int getSelectedPosition(){
			return mSelectedPos;
		}
		
		public long getSelectedItemID() {
			Expense expenses = mItems.get(mSelectedPos);
			
			return expenses._ID;
		}
		
		public Expense getItem() {
			return super.getItem(mSelectedPos);
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = convertView;
			if (v == null) {
				LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.expenses_edit_list_item, null);
			}
			
			LinearLayout ll = (LinearLayout)v.findViewById(R.id.expense_list_item);
			//ll.setFocusableInTouchMode(true);
			
			if(mSelectedPos == position){
				//name.setTextColor(Color.parseColor(getApplicationContext().getString(R.color.gold)));
				ll.setBackgroundResource(R.drawable.list_item_selected);
			} else {
				//name.setTextColor(Color.parseColor(getApplicationContext().getString(R.color.light_gray)));
				ll.setBackgroundResource(R.drawable.list_item_unselected);
			}
			
			Expense expense = mItems.get(position);
			
			if (expense != null) {
				TextView tv = (TextView) v.findViewById(R.id.expense_name);
				TextView id = (TextView) v.findViewById(R.id.expense_id);
				TextView amt = (TextView) v.findViewById(R.id.expense_amount);
				
				if (tv != null) { 
					tv.setText("Name: " + expense.NAME);
					tv.setTextColor(expense.EXPENSE_TYPE.COLOR);
				}
				if (id != null){ id.setText(Long.toString(expense._ID)); }
				
				if (amt != null) { 
					amt.setText("Amount: " + NumberFormat.getCurrencyInstance().format(expense.AMOUNT));
				}
			}
			
			return v;
		}
	}
}